'''
Created on 23/11/2010

@author: Nami
'''

from bk.pygame.ships.game.Weapon import *
from bk.pygame.ships.game.base.Xml2Obj import *
from bk.pygame.ships.game.GBullet import *

WEAPON_PRIMARY = "_1"
WEAPON_SECONDARY = "_2"

class Armory(object):
    '''
    classdocs
    '''

    dic = {}

    cooldown = 0.
    cooldown_max = 0.
    current_weapon_1 = None
    current_weapon_2 = None
    current_weapon = None
    weapon_slot = "w1"
    last_weapon_slot = None
    parent = None
    energy = 0.
    energy_max = 5000.
    shooting = False
    charging = False
    charge = 0.
    charge_max = 0.
    shoot_pending = []
    shoot_time = 0.
    

    def get_weapon(self,key):
        return self.dic[key] if key in self.dic else None 

    def set_weapon(self,key):
        #if shooting, cannot change
        if self.shooting:
            return
        
        #if there is a primary weapon for this slot (key) and that weapon is active       
        if key+WEAPON_PRIMARY in self.dic and self.get_weapon(key+WEAPON_PRIMARY).active:
            self.current_weapon_1 = self.dic[key+WEAPON_PRIMARY]
            if key+WEAPON_SECONDARY in self.dic:
                self.current_weapon_2 = self.dic[key+WEAPON_SECONDARY]
            else:
                self.current_weapon_2 = None
            self.charge = 0.
            self.charging = False
            self.shooting = False
            self.last_weapon_slot = self.weapon_slot
            self.weapon_slot = key

    def switch_weapon(self):
        if not self.last_weapon_slot:
            return
        
        self.set_weapon(self.last_weapon_slot)
        

    def add_energy(self, energy):
        """add energy to the pool, if too much energy return th rest"""
        avaliable_space = self.energy_max - self.energy
        if energy < avaliable_space:
            self.energy = min(self.energy_max, self.energy + energy)
            return 0
        else:
            self.energy = min(self.energy_max,avaliable_space+self.energy)
            return energy-avaliable_space

    def update(self, elapsed, primary, secondary, auxiliar):
        self.cooldown = max(0,self.cooldown-elapsed)
        #activate weapons
        for w in self.dic.itervalues():
            if w.active:
                continue
            if self.energy >= float(w.energy_to_activate):
                w.active = True
                
        #shoot
        if self.shooting:
            self.update_shoot(float(elapsed))
        else:
            if self.charging and not self.cooldown > 0.:
                #control charge
                if self.charging == WEAPON_PRIMARY:
                    if primary == 2:
                        self.charge = min(self.charge + 1*elapsed,self.current_weapon_1.charge_max)
                    else:
                        self.shoot(self.current_weapon_1, elapsed)
                elif self.charging == WEAPON_SECONDARY:
                    if secondary == 2:
                        self.charge = min(self.charge + 1*elapsed,self.current_weapon_2.charge_max)
                    else:
                        self.shoot(self.current_weapon_2, float(elapsed))
            else:
                if primary > 0:
                    if self.current_weapon_1.is_charged_shoot:
                        self.charging = WEAPON_PRIMARY
                        self.charge_max = self.current_weapon_1.charge_max
                    else:
                        self.shoot(self.current_weapon_1, float(elapsed))
                elif secondary > 0 and self.current_weapon_2 and self.current_weapon_2.active:
                    if self.current_weapon_2.is_charged_shoot:
                        self.charging = WEAPON_SECONDARY
                        self.charge_max = self.current_weapon_2.charge_max
                    else:
                        self.shoot(self.current_weapon_2, float(elapsed))

    def shoot(self, weapon, elapsed):
        if self.cooldown > 0. or\
        not weapon.active or\
        self.shooting or\
        self.energy < float(weapon.energy_to_shoot):
            return
        
        self.current_weapon = weapon
        self.shooting = True
        
        if self.charging:
            #charged shoot
            bullet_number = int(self.charge / weapon.charge_step)
            self.shoot_pending = sorted(weapon.bullet_dic.values(),key=lambda bullet: bullet.order)[0:bullet_number]
            self.charge = 0.
        else:
            #normal shoot
            self.shoot_pending = list(weapon.bullet_dic.values())
        
        self.shoot_time = 0.
        self.update_shoot(float(elapsed))

    def update_shoot(self, elapsed):
        #weird bug, testing fix
        time_elapsed = float(elapsed)
        self.shoot_time += time_elapsed

        to_remove = []
        #iterate pending bullets
        for x in xrange(len(self.shoot_pending)):
            b = self.shoot_pending[x]
            #if the time offset allows the bullet to be shoot
            if b.time_offset <= self.shoot_time:
                #if enough energy, shoot the bullet, else spend energy but dont shoot muhahahaha
                if b.energy <= self.energy:
                    #create graphical bullet
                    new_bullet = GBullet(KCLASS_SHOOT,KSCLASS_SHOOTBULLET,b,self.parent)
                    self.parent.world.add_entity(new_bullet)
                #spend energy and remove processed bullet
                self.energy -= b.energy
                to_remove.append(x)
                
        #remove used bullets
        to_remove.sort()
        for i in to_remove[::-1]:
            del self.shoot_pending[i]     

        #if no more bullets left, weapon has finished shooting
        if len(self.shoot_pending) == 0:
            self.charging = False
            self.shooting = False
            self.cooldown = float(self.current_weapon.cooldown)
            self.cooldown_max = self.cooldown
            self.shoot_time = 0

    def __init__(self,parent,weapons_file):
        '''
        Constructor
        '''
        self.parent = parent
        res = open(weapons_file,"r").read()
        armory = xml2obj(res)
        self.dic = {}
        for w in armory.weapon:
            new_weapon = Weapon(self,w)
            self.dic[new_weapon.id] = new_weapon
        
        self.set_weapon("w1")